#include <iostream>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <ctime>
#include <cassert>
#include <functional>
#include <vector>
#include <string>
#include <cstdio>
inline void MakeSeed()
{
    srand((unsigned int)time(nullptr) ^ getpid());
}
using namespace std;

class SubEP
{
public:
    SubEP(pid_t subId, int writeFd)
        :_subId(subId), _writeFd(writeFd)
    {
        char buffer[1024];
        snprintf(buffer, sizeof buffer, "pid: %d [pid:(%d) writeFd:(%d)", _num++, _subId, _writeFd);
        _name = buffer;
    }
public:
    string _name;
    pid_t _subId;
    int _writeFd;
    static int _num;
};
int SubEP::_num = 0;

enum{subProcessNum = 3};
using func_t = std::function<void(void)>;

//加载任务表
void LoadTask(vector<func_t>& taskV)
{
    taskV.push_back([]{
        cout << getpid() <<  " 任务1 \n" << endl;
        sleep(1);
    });
    taskV.push_back([]{
        cout << getpid() <<  " 任务2 \n" << endl;
        sleep(1);
    });
    taskV.push_back([]{
        cout << getpid() <<  " 任务3 \n" << endl;
        sleep(1);
    });
}

int ReceiveTaskIndex(int readFd)
{
    int ret = 0;
    ssize_t n = read(readFd, &ret, sizeof(int));
    if(sizeof(int) == n)    return ret;
    else if(0 == n) return -1;
    else return 0;
}

//创建子进程
void CreateSubProcess(vector<SubEP>& subs, const vector<func_t>& taskV)
{
    int taskNum = taskV.size();
    vector<int> deleteFd;
    for(int i = 0; i < subProcessNum; ++i)
    {
        int fds[2];
        int n = pipe(fds);
        assert(0 == n);
        (void)n;

        pid_t id = fork();
        if(0 == id) //子进程
        {
            for(auto e : deleteFd)
                close(e);
            close(fds[1]); 

            while(1)
            {
                //获取任务
                int taskIndex = ReceiveTaskIndex(fds[0]);
                if(taskIndex >= 0 && taskIndex < taskNum)
                {
                    taskV[taskIndex]();
                }
                else
                {
                    break;
                }
            }
            _exit(0);
        }
        //父进程
        close(fds[0]);
        subs.push_back(SubEP(id, fds[1]));
        deleteFd.push_back(fds[1]);
    }
}

//发送信息
void SendMessage(const SubEP& sub, int taskIndex)
{
    std::cout << "send task num: " << taskIndex << " send to -> " << sub._name << std::endl;
    ssize_t n = write(sub._writeFd, &taskIndex, sizeof taskIndex);
    assert(n == sizeof(int));
    (void)n;
}

//走到这里一定是父进程，向子进程负载均衡的发送任务码
void LoadBlanceControl(const vector<SubEP>& subs, const vector<func_t>& taskV, int cnt)
{
    int subNum = subs.size();
    int taskNum = taskV.size();
    bool forever = (cnt == 0 ? true : false);
    while(1)
    {
        //选择发送的进程
        int subi = rand() % subNum;
        //选择发送的任务码
        int taski = rand() % taskNum;
        //开始发送
        SendMessage(subs[subi], taski);
        sleep(1);
        if(!forever)
        {
            cnt--;
            if(cnt == 0) break;
        }
    }
    for(int i = 0; i < subNum; ++i)
        close(subs[i]._writeFd);
}

void FreeSub(const vector<SubEP>& subs) //回收子进程
{
    for(const auto& e : subs)
    {
        int n = waitpid(e._subId, nullptr, 0);
        std::cout << "wait sub process: " << e._subId << " success" << std::endl;
        assert(n > 0);
        (void)n;
    }
}
int main()
{
    vector<func_t> taskV; //任务表
    vector<SubEP> subV;  //管理子进程的表

    LoadTask(taskV); //加载任务表
    
    CreateSubProcess(subV, taskV); //创建子进程

    //走到这里一定是父进程，向子进程负载均衡的发送任务码
    int cnt = 5;
    LoadBlanceControl(subV, taskV, cnt); //当cnt是0时表示一直发，大于0表示发送任务数量

    FreeSub(subV); //回收子进程
    return 0;
}